package com.blue.base.oauth.server.config.authorize.code;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.Authentication;
import org.springframework.security.oauth2.common.util.OAuth2Utils;
import org.springframework.security.oauth2.provider.AuthorizationRequest;
import org.springframework.security.oauth2.provider.OAuth2RequestFactory;
import org.springframework.security.oauth2.provider.approval.Approval;
import org.springframework.security.oauth2.provider.approval.ApprovalStore;
import org.springframework.security.oauth2.provider.approval.ApprovalStoreUserApprovalHandler;
import org.springframework.security.oauth2.provider.client.JdbcClientDetailsService;

import java.util.*;

/**
 * 此处的approvalHandler的作用：处理用户在授权页面，也就是access_confirm.html的操作
 * 1.将每次请求的code码，存储到jdbc表oauth_approvals中去
 * 2.访问api请求code码时，除了要对其记录到数据库，还会根据规则：
 * 【1.oauth_client_details的autoapprove字段判断是否该客户端可信，可信则跳过允许授权页面，直接返回code码，如果不可信应用，则进入规则2判断】
 * 【2.如果oauth_approvals表中存在已经授权的记录，则也可以判断该客户端可信，也会直接跳过，如果没有，则还是需要走授权页面access_confirm.html的操作】
 * 有兴趣的同学可以在下面的代码：
 *
 * @author liulei
 * @version 1.0
 * @see org.springframework.security.oauth2.provider.approval.ApprovalStoreUserApprovalHandler#checkForPreApproval(AuthorizationRequest, Authentication)
 */
public class BataApprovalHandler extends ApprovalStoreUserApprovalHandler {

    private int approvalExpirySeconds = -1;

    @Autowired
    private ApprovalStore approvalStore;

    public BataApprovalHandler(JdbcClientDetailsService clientDetailsService, ApprovalStore approvalStore, OAuth2RequestFactory oAuth2RequestFactory) {
        this.setApprovalStore(approvalStore);
        this.setClientDetailsService(clientDetailsService);
        this.setRequestFactory(oAuth2RequestFactory);
    }

    /**
     * 照搬父源码即可，如果需要改动则修改
     */
    @Override
    public AuthorizationRequest updateAfterApproval(AuthorizationRequest authorizationRequest, Authentication userAuthentication) {
        // Get the approved scopes
        Set<String> requestedScopes = authorizationRequest.getScope();
        Set<String> approvedScopes = new HashSet<>();
        Set<Approval> approvals = new HashSet<>();

        Date expiry = computeExpiry();

        // Store the scopes that have been approved / denied
        Map<String, String> approvalParameters = authorizationRequest.getApprovalParameters();
        for (String requestedScope : requestedScopes) {
            String approvalParameter = OAuth2Utils.SCOPE_PREFIX + requestedScope;
            String value = approvalParameters.get(approvalParameter);
            value = value == null ? "" : value.toLowerCase();
            if ("true".equals(value) || value.startsWith("approve") || value.equals("on")) {
                approvedScopes.add(requestedScope);
                approvals.add(new Approval(userAuthentication.getName(), authorizationRequest.getClientId(),
                        requestedScope, expiry, Approval.ApprovalStatus.APPROVED));
            } else {
                approvals.add(new Approval(userAuthentication.getName(), authorizationRequest.getClientId(),
                        requestedScope, expiry, Approval.ApprovalStatus.DENIED));
            }
        }
        approvalStore.addApprovals(approvals);

        boolean approved = true;
        authorizationRequest.setScope(approvedScopes);
        if (approvedScopes.isEmpty() && !requestedScopes.isEmpty()) {
            approved = false;
        }
        authorizationRequest.setApproved(approved);
        return authorizationRequest;
    }

    /**
     * 计算过期时间
     */
    private Date computeExpiry() {
        Calendar expiresAt = Calendar.getInstance();
        if (approvalExpirySeconds == -1) {
            // 默认一个月过期
            expiresAt.add(Calendar.MONTH, 1);
        } else {
            expiresAt.add(Calendar.SECOND, approvalExpirySeconds);
        }
        return expiresAt.getTime();
    }

}
